package utils

import (
	"encoding/binary"
	"fmt"
)

// CoAPOptionsResult CoAP选项解析结果
type CoAPOptionsResult struct {
	OptionsLength int    // Options部分的总长度（字节）
	OptionsBytes  []byte // Options部分的原始二进制数据
	PayloadBytes  []byte // Payload部分的原始二进制数据
}

// ParseCoAPOptions 解析CoAP消息中的Options和Payload
func ParseCoAPOptions(data []byte) (*CoAPOptionsResult, map[string]string, error) {
	optionsData := make(map[string]string)

	if len(data) == 0 {
		return nil, nil, fmt.Errorf("empty data")
	}

	result := &CoAPOptionsResult{
		OptionsLength: 0,
		OptionsBytes:  []byte{},
		PayloadBytes:  []byte{},
	}

	prevOptionNumber := uint16(0) // 前一个Option的编号
	offset := 0                   // 当前解析位置

	for offset < len(data) {
		// 检查是否到达Payload分隔符
		if data[offset] == 0xFF {
			result.OptionsBytes = append(result.OptionsBytes, []byte{0xFF}...)
			offset++ // 跳过0xFF
			if offset < len(data) {
				result.PayloadBytes = data[offset:]
			}
			break
		}

		// 记录当前Option的起始位置
		optionStart := offset

		// 步骤1: 读取第一个字节
		if offset >= len(data) {
			return nil, nil, fmt.Errorf("insufficient data at offset %d", offset)
		}
		firstByte := data[offset]
		offset++

		// 步骤2: 解析Delta和Length的初始值
		deltaNibble := (firstByte >> 4) & 0x0F
		lengthNibble := firstByte & 0x0F

		// 步骤3: 处理扩展值
		delta, _, err := parseExtendedField(data, &offset, deltaNibble)
		if err != nil {
			return nil, nil, err
		}

		length, _, err := parseExtendedField(data, &offset, lengthNibble)
		if err != nil {
			return nil, nil, err
		}

		// 步骤4: 计算实际Option号码
		optionNumber := prevOptionNumber + delta
		prevOptionNumber = optionNumber

		// 步骤5: 读取Option Value
		if offset+int(length) > len(data) {
			return nil, nil, fmt.Errorf("insufficient data for option value at offset %d", offset)
		}
		// optionValue := data[offset : offset+int(length)]
		offset += int(length)

		// 记录完整的Option二进制数据（包括头部和值）
		optionEnd := offset
		result.OptionsBytes = append(result.OptionsBytes, data[optionStart:optionEnd]...)
		//获取option具体项
		optionsData[getOptionKey(optionNumber)] = string(data[optionEnd-int(length) : optionEnd])

	}

	result.OptionsLength = len(result.OptionsBytes)
	return result, optionsData, nil
}

// 解析扩展字段（处理Delta或Length需要扩展的情况）
func parseExtendedField(data []byte, offset *int, nibble byte) (uint16, []byte, error) {
	var value uint16
	var extensionBytes []byte

	switch nibble {
	case 13:
		// 需要1字节扩展
		if *offset+1 > len(data) {
			return 0, nil, fmt.Errorf("insufficient data for 1-byte extension at offset %d", *offset)
		}
		value = uint16(data[*offset]) + 13
		extensionBytes = data[*offset : *offset+1]
		*offset += 1

	case 14:
		// 需要2字节扩展
		if *offset+2 > len(data) {
			return 0, nil, fmt.Errorf("insufficient data for 2-byte extension at offset %d", *offset)
		}
		value = binary.BigEndian.Uint16(data[*offset:*offset+2]) + 269
		extensionBytes = data[*offset : *offset+2]
		*offset += 2

	case 15:
		// CoAP规范中不使用4字节扩展（保留）
		return 0, nil, fmt.Errorf("4-byte extension (nibble 15) is reserved and not supported")

	default:
		// 无需扩展，直接使用nibble值
		value = uint16(nibble)
		extensionBytes = []byte{}
	}

	return value, extensionBytes, nil
}

func getOptionKey(optionId uint16) string {
	customNames := map[uint16]string{
		1:  "If-Match",
		3:  "URI-Host",
		4:  "ETag",
		5:  "If-None-Match",
		6:  "Observe",
		7:  "URI-Port",
		8:  "Location-Path",
		11: "URI-Path",
		12: "Content-Format",
		14: "Max-Age",
		15: "URI-Query",
		17: "Accept",
		20: "Location-Query",
		23: "Block2",
		27: "Block1",
		28: "Size2",
		35: "Proxy-URI",
		39: "Proxy-Scheme",
		60: "Size1",
		// 自定义option项
		2048: "SESSION_ID",
		2056: "PUUID",
		2057: "PLUGIN",
		2058: "LOCAL_ER",
		2053: "SEQ_NUM_ID",
		2049: "ACCESS_TOKEN_ID",
		2050: "REQ_ID",
		2051: "DEV_ID",
		2052: "USER_ID",
		3000: "CLIENT_ID",
		3001: "APP_ID",
		// 添加更多自定义选项名称...
	}

	if name, exists := customNames[optionId]; exists {
		return name
	}

	return ""
}
